/********************************************************************************************************
 *
 *  The simulated MIPS Processor stat of the source process
 *
 *******************************************************************************************************/
#ifndef MIPSPROCESSORSTATE_H
#define MIPSPROCESSORSTATE_H


#include <iostream>
#include "crossbit/ProcessorState.h"

namespace crossbit {

    class MIPSProcessorState : public ProcessorState
    {
        public:
            /* total 35 internal registers numbered 0, 1, ..., 33 */
            enum PISA {
                $zero = 0,				// $0, zero-valued souce
                $at,					// $1, reserved by assembler
                $v0, $v1,				// $2-$3, fn return result regs
                $a0, $a1, $a2, $a3,			// $4-$7, fn argument value regs
                $t0, $t1, $t2, $t3, $t4, $t5, $t6, $t7, // $8-$15, temp regs, caller saved, general-purpose
                $s0, $s1, $s2, $s3, $s4, $s5, $s6, $s7, // $16-$23, saved regs, callee saved, general-purpose
                $t8, $t9,				// $24-$25, temp regs, caller saved, general-purpose
                $k0, $k1,				// $26-$27, reserved by OS
                $gp,					// $28, global pointer
                $sp,					// $29, stack pointer
                $s8,					// $30, saved reg, callee saved
                $ra,					// $31, return address reg
                $hi,					// high result register
                $lo,					// low result register
                EOR					//end of register
            };

            enum FP {					//Float point register
                $f0 = 0,
                $f1,
                $f2,
                $f3,
                $f4,
                $f5,
                $f6,
                $f7,
                $f8,
                $f9,
                $f10,
                $f11,
                $f12,
                $f13,
                $f14,
                $f15,
                $f16,
                $f17,
                $f18,
                $f19,
                $f20,
                $f21,
                $f22,
                $f23,
                $f24,
                $f25,
                $f26,
                $f27,
                $f28,
                $f29,
                $f30,
                $f31,
                $fcc,					//Float point condition code register
                $fcw,EOFR
            };


            MIPSProcessorState() 
            {
                // initialize registers to zero
                UTIL::XTMemset((void *)&regs, 0, sizeof(regs));
                UTIL::XTMemset((void *)&fp_regs, 0, sizeof(fp_regs));
            }


            MIPSProcessorState *getProcessorState()
            {
                return this;
            }
            // Get the memory address of the simulated register
            XTMemAddr get(XTRegNum reg) const
            {
                return (XTMemAddr) (regs + reg);
            }

            // Get the value of the simulated register
            XTInt32 reg(XTRegNum reg) const
            {
                return regs[reg];
            }

            // Set the value of simulated register
            void put(XTRegNum reg, XTInt32 value)
            {
                regs[reg] = value;
            }

            // Get the number of *general-purpose* register
            int size() const
            {
                // $0-32, $hi, $lo
                return EOR;
            }

            XTMemAddr fpGet(XTRegNum reg) const
            {
                return (XTMemAddr) (fp_regs + reg);
            }

            // Get the value of the simulated register
            XTInt32 fpReg(XTRegNum reg) const
            {
                return fp_regs[reg];
            }

            // Set the value of simulated register
            void fpPut(XTRegNum reg, XTInt32 value)
            {
                fp_regs[reg] = value;
            }

            // Get the number of float-point register
            int fpSize() const
            {
                // $0-31, $fcc
                return EOFR;
            }

            MIPSProcessorState( const MIPSProcessorState& state )
            {
                int i;

                for( i = 0; i < size(); i ++ )
                {
                    regs[i] = state.regs[i];
                }

                for( i = 0; i < fpSize(); i ++ )
                {
                    fp_regs[i] = state.fp_regs[i];
                }
            }

            const MIPSProcessorState& operator= ( const MIPSProcessorState& state )
            {
                int i;

                for( i = 0; i < size(); i ++ )
                {
                    regs[i] = state.regs[i];
                }

                for( i = 0; i < fpSize(); i ++ )
                {
                    fp_regs[i] = state.fp_regs[i];
                }
                return *this;
            }

            // Dump the register file
            void dump()
            {
                std::cout << "MIPS Register File Dump: " << std::endl
                    << "\t$zero 0x"<< std::hex << *(XTUint32*)&regs[$zero]<<std::endl
                    << "\t$at: 0x" << std::hex << *(XTUint32*)&regs[$at] << std::endl
                    << "\t$v0: 0x" << std::hex <<  *(XTUint32 *)&regs[$v0] << std::endl
                    << "\t$v1: 0x" << std::hex << *(XTUint32 *)&regs[$v1] <<  std::endl
                    << "\t$a0: 0x" << std::hex << *(XTUint32 *)&regs[$a0] <<  std::endl
                    << "\t$a1: 0x" << std::hex << *(XTUint32 *)&regs[$a1] <<  std::endl 
                    << "\t$a2: 0x" << std::hex << *(XTUint32 *)&regs[$a2] <<  std::endl
                    << "\t$a3: 0x" << std::hex << *(XTUint32 *)&regs[$a3] <<  std::endl
                    << "\t$t0: 0x" << std::hex << *(XTUint32 *)&regs[$t0] <<  std::endl
                    << "\t$t1: 0x" << std::hex << *(XTUint32 *)&regs[$t1] <<  std::endl
                    << "\t$t2: 0x" << std::hex << *(XTUint32 *)&regs[$t2] <<  std::endl
                    << "\t$t3: 0x" << std::hex << *(XTUint32 *)&regs[$t3] <<  std::endl
                    << "\t$t4: 0x" << std::hex << *(XTUint32 *)&regs[$t4] <<  std::endl
                    << "\t$t5: 0x" << std::hex << *(XTUint32 *)&regs[$t5] <<  std::endl
                    << "\t$t6: 0x" << std::hex << *(XTUint32 *)&regs[$t6] <<  std::endl
                    << "\t$t7: 0x" << std::hex << *(XTUint32 *)&regs[$t7] <<  std::endl
                    << "\t$s0: 0x" << std::hex << *(XTUint32 *)&regs[$s0] <<  std::endl
                    << "\t$s1: 0x" << std::hex << *(XTUint32 *)&regs[$s1] <<  std::endl
                    << "\t$s2: 0x" << std::hex << *(XTUint32 *)&regs[$s2] <<  std::endl
                    << "\t$s3: 0x" << std::hex << *(XTUint32 *)&regs[$s3] <<  std::endl
                    << "\t$s4: 0x" << std::hex << *(XTUint32 *)&regs[$s4] <<  std::endl
                    << "\t$s5: 0x" << std::hex << *(XTUint32 *)&regs[$s5] <<  std::endl
                    << "\t$s6: 0x" << std::hex << *(XTUint32 *)&regs[$s6] <<  std::endl
                    << "\t$s7: 0x" << std::hex << *(XTUint32 *)&regs[$s7] <<  std::endl
                    << "\t$t8: 0x" << std::hex << *(XTUint32 *)&regs[$t8] <<  std::endl
                    << "\t$t9: 0x" << std::hex << *(XTUint32 *)&regs[$t9] <<  std::endl
                    << "\t$k0: 0x" << std::hex << *(XTUint32 *)&regs[$k0] <<  std::endl
                    << "\t$k1: 0x" << std::hex << *(XTUint32 *)&regs[$k1] <<  std::endl
                    << "\t$gp: 0x" << std::hex << *(XTUint32 *)&regs[$gp] <<  std::endl
                    << "\t$sp: 0x" << std::hex << *(XTUint32 *)&regs[$sp] <<  std::endl
                    << "\t$s8: 0x" << std::hex << *(XTUint32 *)&regs[$s8] <<  std::endl
                    << "\t$ra: 0x" << std::hex << *(XTUint32 *)&regs[$ra] <<  std::endl
                    << "\t$hi: 0x" << std::hex << *(XTUint32 *)&regs[$hi] <<  std::endl
                    << "\t$lo: 0x" << std::hex << *(XTUint32 *)&regs[$lo] <<  std::endl
                    << "PISA Float Point Register Dump:" << std::endl;

                for ( XTInt32 i = 0; i < 34; i++) {
                    std::cout << "\t$f" <<(XTInt32)i<< ": 0x"
                        << std::hex << fp_regs[i] 
                        << std::endl;
                }

            }

			// switch virtual regs
			virtual void switchRegs()
			{
				UTIL::XTMemcpy((void *)&bak_regs, (void *)&regs, sizeof(regs));
				UTIL::XTMemcpy((void *)&bak_fp_regs, (void *)&fp_regs, sizeof(fp_regs));
			}

			void restoreRegs()
			{
				UTIL::XTMemcpy((void *)&regs, (void *)&bak_regs, sizeof(regs));
				UTIL::XTMemcpy((void *)&fp_regs, (void *)&bak_fp_regs, sizeof(fp_regs));
			}
        private:
            volatile XTInt32 regs[EOR];
            volatile XTInt32 bak_regs[EOR];
            volatile XTInt32 fp_regs[EOFR];
            volatile XTInt32 bak_fp_regs[EOFR];
    };

}

#endif
